﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace MMD_Morph_NoteHelp
{
    public struct PairedControlData
    {
        public string ComboBoxText { get; set; }
        public string EditValue { get; set; }
    }

    // ======================= 
    //    Win32 API相关
    //    封装了所有与Windows底层API交互的功能，如查找窗口、控件，发送消息等
    // =====================
    public class Win32Helper
    {
        #region --- Win32 API 声明 (P/Invoke) ---

        // 查找窗口
        [DllImport("user32.dll", SetLastError = true)]
        public static extern IntPtr FindWindow(string lpClassName, string lpWindowName);

        [DllImport("user32.dll", SetLastError = true)]
        public static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string lpszClass, string lpszWindow);

        // 获取控件文本
        [DllImport("user32.dll", CharSet = CharSet.Auto)]
        public static extern int GetWindowText(IntPtr hWnd, StringBuilder lpString, int nMaxCount);

        [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
        public static extern int GetWindowTextLength(IntPtr hWnd);

        // 枚举子窗口
        [DllImport("user32.dll")]
        public static extern bool EnumChildWindows(IntPtr hwndParent, EnumWindowsProc lpEnumFunc, IntPtr lParam);
        public delegate bool EnumWindowsProc(IntPtr hWnd, IntPtr lParam);

        // 获取类名
        [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
        public static extern int GetClassName(IntPtr hWnd, StringBuilder lpClassName, int nMaxCount);

        // 发送消息
        [DllImport("user32.dll", CharSet = CharSet.Auto)]
        public static extern IntPtr SendMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);

        [DllImport("user32.dll", CharSet = CharSet.Auto)]
        public static extern IntPtr SendMessage(IntPtr hWnd, uint Msg, int wParam, StringBuilder lParam);

        // === 用于发送字符串 ===
        [DllImport("user32.dll", CharSet = CharSet.Auto)]
        public static extern IntPtr SendMessage(IntPtr hWnd, uint Msg, IntPtr wParam, string lParam);

        [DllImport("user32.dll", ExactSpelling = true, CharSet = CharSet.Auto)]
        public static extern IntPtr GetParent(IntPtr hWnd);
        [DllImport("user32.dll", SetLastError = true)]
        public static extern int GetWindowLong(IntPtr hWnd, int nIndex);

        [return: MarshalAs(UnmanagedType.Bool)]
        [DllImport("user32.dll", SetLastError = true)]
        public static extern bool PostMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);

        // === SendInput 的结构体和声明 ===
        [StructLayout(LayoutKind.Sequential)]
        public struct KEYBDINPUT
        {
            public ushort wVk;
            public ushort wScan;
            public uint dwFlags;
            public uint time;
            public IntPtr dwExtraInfo;
        }

        [StructLayout(LayoutKind.Sequential)]
        public struct INPUT
        {
            public int type;
            public INPUTUNION u;
        }

        [StructLayout(LayoutKind.Explicit)]
        public struct INPUTUNION
        {
            [FieldOffset(0)]
            public KEYBDINPUT ki;
        }

        [DllImport("user32.dll")]
        public static extern uint SendInput(uint nInputs, [MarshalAs(UnmanagedType.LPArray), In] INPUT[] pInputs, int cbSize);

        // === 激活窗口 ===
        [DllImport("user32.dll")]
        [return: MarshalAs(UnmanagedType.Bool)]
        public static extern bool SetForegroundWindow(IntPtr hWnd);

        [DllImport("user32.dll")]
        [return: MarshalAs(UnmanagedType.Bool)]
        public static extern bool IsIconic(IntPtr hWnd); // 检查窗口是否最小化

        [DllImport("user32.dll")]
        public static extern bool ShowWindow(IntPtr hWnd, int nCmdShow); // 显示/恢复窗口
        private const int SW_RESTORE = 9;

        // 消息常量
        public const uint WM_GETTEXT = 0x000D; // 获取文本
        public const uint WM_GETTEXTLENGTH = 0x000E; // 获取文本长度
        public const uint CB_GETCURSEL = 0x0147; // 获取ComboBox当前选中项索引
        public const uint CB_GETLBTEXT = 0x0148; // 获取ComboBox指定索引的文本
        public const uint CB_GETCOUNT = 0x0146; // 获取ComboBox项数
        public const uint CB_SETCURSEL = 0x014E; // 设置ComboBox当前选中项
        public const uint WM_SETTEXT = 0x000C;      // 设置文本
        public const uint CB_FINDSTRINGEXACT = 0x0158; // 精确查找ComboBox中的字符串索引
        public const uint WM_COMMAND = 0x0111; // 通知父窗口某个控件发生了事件
        public const int EN_CHANGE = 0x0300; // Edit控件内容改变通知码
        public const int GWL_ID = -12;       // 用于获取控件的ID
        public const uint BM_CLICK = 0x00F5; // 点击按钮
        public const uint WM_LBUTTONDOWN = 0x0201; // 鼠标左键按下
        public const uint WM_LBUTTONUP = 0x0202;   // 鼠标左键抬起

        // 获取控件文本的辅助方法 (基础方法，最稳定)
        public static string GetControlText(IntPtr hWnd)
        {
            try
            {
                // 先尝试用 GetWindowTextLength/GetWindowText
                int length = GetWindowTextLength(hWnd);
                if (length > 0)
                {
                    StringBuilder builder = new StringBuilder(length + 1);
                    GetWindowText(hWnd, builder, builder.Capacity);
                    return builder.ToString();
                }

                // 如果失败，尝试用 SendMessage WM_GETTEXT
                IntPtr lenPtr = SendMessage(hWnd, WM_GETTEXTLENGTH, IntPtr.Zero, IntPtr.Zero);
                int len = (int)lenPtr;
                if (len > 0)
                {
                    StringBuilder sb = new StringBuilder(len + 1);
                    IntPtr intPtr = SendMessage(hWnd, WM_GETTEXT, (IntPtr)(len + 1), sb);
                    return sb.ToString();
                }

                return string.Empty;
            }
            catch (Exception ex)
            {
                Debug.WriteLine($"获取控件文本失败: {ex.Message}");
                return string.Empty;
            }
        }

        private static IntPtr SendMessage(IntPtr hWnd, uint wM_GETTEXT, IntPtr intPtr, StringBuilder sb)
        {
            throw new NotImplementedException();
        }

        // 在Win32Helper中添加缓存字符串构建器
        private static readonly StringBuilder _textBuilder = new StringBuilder(256);

        // 获取 ComboBox 当前选中项 (仅在需要精确获取选中项时使用，监控时不建议使用)
        public static string GetComboBoxSelectedItem(IntPtr hWnd)
        {
            try
            {
                int count = (int)SendMessage(hWnd, CB_GETCOUNT, IntPtr.Zero, IntPtr.Zero);
                if (count <= 0) return string.Empty;

                int selectedIndex = (int)SendMessage(hWnd, CB_GETCURSEL, IntPtr.Zero, IntPtr.Zero);

                if (selectedIndex < 0)
                {
                    // 如果没有选中项，回退到获取显示的文本
                    return GetControlText(hWnd);
                }

                _textBuilder.Clear();
                // 注意：这里必须用正确的 SendMessage 重载
                SendMessage(hWnd, CB_GETLBTEXT, selectedIndex, _textBuilder);
                return _textBuilder.ToString();
            }
            catch (Exception ex)
            {
                Debug.WriteLine($"获取ComboBox选中项失败: {ex.Message}");
                return GetControlText(hWnd); // 发生异常时回退到基础方法
            }
        }

        // 查找进程窗口
        public static IntPtr FindProcessWindow(string processName)
        {
            try
            {
                Process[] processes = Process.GetProcessesByName(processName);
                if (processes.Length > 0 && processes[0].MainWindowHandle != IntPtr.Zero)
                {
                    return processes[0].MainWindowHandle;
                }
                return IntPtr.Zero;
            }
            catch (Exception ex)
            {
                Debug.WriteLine($"查找进程窗口失败: {ex.Message}");
                return IntPtr.Zero;
            }
        }

        // 根据类名获取控件文本 (简化版，回归稳定性)
        public static string ControlGetText(string classNN, IntPtr hwndParent)
        {
            if (hwndParent == IntPtr.Zero) return string.Empty;

            try
            {
                // 注意：这里的 FindControlByClass 实现可能需要依赖 ControlMonitorService 里的那种精确 ClassNN 查找
                // 如果只是简单按类名查找可能不准确。
                // 鉴于 ControlMonitorService 已经实现了更好的查找，这里保留基本功能即可。
                IntPtr controlHwnd = FindControlByClass(hwndParent, classNN);
                if (controlHwnd != IntPtr.Zero)
                {
                    return GetControlText(controlHwnd);
                }
            }
            catch { }
            return string.Empty;
        }

        // 通过类名查找控件 (简单查找，可能不适用于有多个相同类名的子窗口)
        public static IntPtr FindControlByClass(IntPtr hwndParent, string className)
        {
            IntPtr foundControl = IntPtr.Zero;
            EnumChildWindows(hwndParent, (hWnd, lParam) =>
            {
                StringBuilder classBuilder = new StringBuilder(256);
                GetClassName(hWnd, classBuilder, classBuilder.Capacity);
                if (classBuilder.ToString() == className)
                {
                    foundControl = hWnd;
                    return false; // 停止枚举
                }
                return true; // 继续枚举
            }, IntPtr.Zero);
            return foundControl;
        }

        // 简单的窗口查找方法
        public static IntPtr FindWindowByTitle(string windowTitle)
        {
            return FindWindow(null, windowTitle);
        }

        /// 获取控件的ID
        public static int GetWindowId(IntPtr hWnd)
        {
            const int GWL_ID = -12;
            return GetWindowLong(hWnd, GWL_ID);
        }

        /// <summary>
        /// 设置控件的文本
        /// </summary>
        public static void SetControlText(IntPtr hWnd, string text)
        {
            SendMessage(hWnd, WM_SETTEXT, IntPtr.Zero, text);
        }

        /// <summary>
        /// 在 ComboBox 中找到指定文本的索引，然后选中它
        /// </summary>
        public static bool SelectComboBoxItem(IntPtr hWnd, string itemText)
        {
            // 第一个参数-1表示从头开始搜索
            IntPtr indexPtr = SendMessage(hWnd, CB_FINDSTRINGEXACT, (IntPtr)(-1), itemText);
            int index = indexPtr.ToInt32();

            if (index != -1)
            {
                SendMessage(hWnd, CB_SETCURSEL, (IntPtr)index, IntPtr.Zero);
                IntPtr parentHWnd = GetParent(hWnd);
                int controlId = GetWindowLong(hWnd, GWL_ID);
                const int CBN_SELCHANGE = 1;
                IntPtr wParam = (IntPtr)((CBN_SELCHANGE << 16) | (controlId & 0xFFFF));
                SendMessage(parentHWnd, WM_COMMAND, wParam, hWnd);
                return true;
            }
            return false;
        }

        #endregion

        #region --- AHK 脚本调用 ---

        // === 调用AHK脚本的通用方法 ===
        private static async Task CallAHK(string scriptName, params string[] args)
        {
            string ahkAppPath = Path.Combine(Application.StartupPath, "config", scriptName);
            if (!File.Exists(ahkAppPath))
            {
                // MessageBox.Show($"错误：未找到核心组件 {Path.Combine("config", scriptName)}！", "组件丢失", MessageBoxButtons.OK, MessageBoxIcon.Error);
                MessageBox.Show(L10n.Get("FoundCorecomponent"), L10n.Get("Componentmissing"), MessageBoxButtons.OK, MessageBoxIcon.Error);
                return;
            }

            // 将所有参数用引号包裹，确保带空格的参数也能正确传递
            string arguments = string.Join(" ", args.Select(arg => $"\"{arg}\""));
            ProcessStartInfo startInfo = new ProcessStartInfo
            {
                FileName = ahkAppPath,
                Arguments = arguments,
                UseShellExecute = true
            };

            // 使用异步方式启动并等待，确保一个任务完成后再开始下一个
            await Task.Run(() =>
            {
                using (Process process = Process.Start(startInfo))
                {
                    process.WaitForExit(); // 等待AHK脚本执行完毕
                }
            });
        }

        // === 导出VMD脚本 ===
        // MainForm.cs
        // private async void Saveoutput_Click
        public static async Task ExportVMDWithAHK(string vmdFilePath)
        {
            await CallAHK("ExportVMD_v2.exe", vmdFilePath); // 导出VMD的脚本 config\ExportVMD.exe
        }

        // === 导入VMD脚本 ===
        // PresetForm.cs
        // private async void PresetApplyButton_Click
        public static async Task ImportVMDWithAHK(string vmdFilePath)
        {
            await CallAHK("ImportVMD_v2.exe", vmdFilePath); // 导入VMD的脚本 config\ImportVMD.exe
        }

        // === 调用填入Edit的脚本 ===
        // ControlMonitorService.cs
        // public async Task<List<string>> ApplyMorphData
        public static async Task SetValueWithAHK(string editClassNN, string value)
        {
            await CallAHK("SetValue.exe", editClassNN, value); // 填写Edit的脚本 config\SetValue.exe 
        }

        // === 最终按下H键注册 ===
        // ControlMonitorService.cs
        // public async Task<List<string>> ApplyMorphData
        public static async Task PressHKeyWithAHK()
        {
            await CallAHK("RegisterAll.exe"); // 最终按下H键的脚本 config\RegisterAll.exe
        }

        #endregion

        #region --- 模拟输入与点击 ---

        // 向按钮发送一个“点击”消息 (同步)
        public static void ClickButton(IntPtr hWnd)
        {
            SendMessage(hWnd, BM_CLICK, IntPtr.Zero, IntPtr.Zero);
        }

        // 使用 PostMessage 模拟真实点击 (异步)
        public static void ClickButtonByPosting(IntPtr hWnd)
        {
            // 模拟一个完整的“按下”和“抬起”过程
            // 使用 PostMessage，把这些消息放进MMD的消息队列里，让它自己处理，更接近真实操作
            PostMessage(hWnd, WM_LBUTTONDOWN, (IntPtr)1, IntPtr.Zero); // 1 表示左键
            Thread.Sleep(20);  // 模拟按下的短暂时间
            PostMessage(hWnd, WM_LBUTTONUP, IntPtr.Zero, IntPtr.Zero);
        }

        // 模拟物理按键 (按下并抬起)
        public static void PressKey(Keys key)
        {
            INPUT[] inputs = new INPUT[2];
            // 按下
            inputs[0] = new INPUT { type = 1, u = new INPUTUNION { ki = new KEYBDINPUT { wVk = (ushort)key, dwFlags = 0 } } };
            // 抬起
            inputs[1] = new INPUT { type = 1, u = new INPUTUNION { ki = new KEYBDINPUT { wVk = (ushort)key, dwFlags = 2 } } }; // dwFlags=2 表示 KEYEVENTF_KEYUP
            SendInput(2, inputs, Marshal.SizeOf(typeof(INPUT)));
        }

        // 激活指定窗口并按下按键
        public static void ActivateAndPressKey(IntPtr hWnd, Keys key)
        {
            // 检查MMD是否被最小化了
            if (IsIconic(hWnd))
            {
                ShowWindow(hWnd, SW_RESTORE); // 如果是，就先把它恢复
                Thread.Sleep(100); // 给窗口一点时间来恢复
            }

            SetForegroundWindow(hWnd); // 激活窗口
            Thread.Sleep(100); // 给系统一点时间来切换焦点
            PressKey(key); // 按下按键
        }
    }

    #endregion
}